<template>
	<div class="gaodeMap">
		<div :id="`container-${mid}`" class="xn-wh">地图资源加载中...</div>
		<div class="absolute right-0" style="top: 80px; width: 300px">
			<a-input
				style="margin-bottom: 20px"
				placeholder="请输入要搜索的地名"
				v-model:value="searchValue"
				@update:value="search"
			/>
			<a-input placeholder="请输入要搜索的区域" v-model:value="areaKeyWord" @update:value="areaSearch">
				<template #addonAfter>
					<a-select v-model:value="areaType" style="width: 100px">
						<a-select-option value="country">国家</a-select-option>
						<a-select-option value="province">省/直辖市</a-select-option>
						<a-select-option value="city">市</a-select-option>
						<a-select-option value="district">区/县 </a-select-option>
						<a-select-option value="biz_area">商圈 </a-select-option>
					</a-select>
				</template>
			</a-input>
		</div>
		<div id="panel" v-show="searchValue"></div>
		<div v-if="areaInfo.show" class="areaInfo">
			<a-descriptions bordered siz="small">
				<a-descriptions-item label="行政区名称">{{ areaInfo.name }}</a-descriptions-item>
				<a-descriptions-item label="城市编码">{{ areaInfo.citycode }}</a-descriptions-item>
				<a-descriptions-item label="区域编码">{{ areaInfo.adcode }}</a-descriptions-item>
				<a-descriptions-item label="行政区划级别">{{ areaInfo.level }}</a-descriptions-item>
				<a-descriptions-item label="经纬度">[{{ areaInfo.center.lng }},{{ areaInfo.center.lat }}]</a-descriptions-item>
				<a-descriptions-item label="操作"
					><a-button type="primary" @click="exportFile(areaInfo.polygon)">导出</a-button></a-descriptions-item
				>
			</a-descriptions>
		</div>
	</div>
	<a-modal title="当前区域面积" v-model:open="areaModal.open" :footer="null">
		<a-form>
			<a-form-item label="区域点坐标">
				<span>
					{{ areaModal.checkPoints }}
				</span>
			</a-form-item>
			<a-form-item label="区域面积">
				<span> {{ areaModal.area }} <span class="ml-1.5">平方米</span> </span>
			</a-form-item>
		</a-form>
	</a-modal>
</template>
<!--AMap官网：https://lbs.amap.com/api/javascript-api-v2/summary-->
<script setup name="GaodeMap">
	window._AMapSecurityConfig = {
		securityJsCode: '5e808557e67fac1a316edba3bbc27161'
	}
	import { onMounted, onUnmounted, shallowRef } from 'vue'
	import AMapLoader from '@amap/amap-jsapi-loader'
	import { message } from 'ant-design-vue'

	const props = defineProps({
		mid: {
			type: Number,
			default: new Date().getTime()
		},
		height: {
			type: Number,
			default: 700
		},
		apiKey: {
			type: String,
			required: true
		},
		center: {
			type: Array
		},
		plugins: {
			type: Array,
			// eslint-disable-next-line vue/require-valid-default-prop
			default: [
				'AMap.ToolBar',
				'AMap.Scale',
				'AMap.HawkEye',
				'AMap.MapType',
				'AMap.Geolocation',
				'AMap.MarkerCluster',
				'AMap.MouseTool',
				'AMap.PlaceSearch',
				'AMap.DistrictSearch'
			]
		},
		viewMode: {
			type: String,
			default: '3D',
			validator(value) {
				return ['2D', '3D'].includes(value)
			}
		},
		zoom: {
			type: Number,
			default: 12
		},
		pitch: {
			type: Number,
			default: 50
		},
		mapStyle: {
			type: String,
			default: 'normal',
			validator(value) {
				return ['normal', 'macaron', 'dark', 'fresh', 'grey'].includes(value)
			}
		},
		markerCluster: {
			type: Boolean,
			default: true
		}
	})

	const emits = defineEmits(['complete', 'markerClick'])

	const gaodeMap = shallowRef(null)
	const gaodeMapMarkerArr = ref([])
	const gaodeMapInfoWindowObj = ref({})

	const gaodeMouseTool = ref(null)
	//mousetool 绘制flag
	let gaodeMouseDagFlag = false

	let checkPoints = []
	let editor = null
	const searchValue = ref('')
	const areaKeyWord = ref('')
	const init = () => {
		AMapLoader.load({
			key: props.apiKey,
			version: '2.0',
			plugins: props.plugins,
			AMapUI: {
				version: '1.1',
				plugins: ['overlay/SimpleMarker', 'overlay/AwesomeMarker']
			}
		})
			.then(() => {
				initMap()
			})
			.catch((e) => {
				console.error(e)
			})
	}

	const getPolygonPoints = (polygon) => {
		if (polygon === null) {
			return []
		}
		let points = polygon.getPath()
		let arr = []
		points.map((v) => {
			arr.push([v.lng, v.lat])
		})
		arr.push(arr[0])
		checkPoints = arr
	}

	let polygon = null
	// 初始化 地图
	const initMap = () => {
		gaodeMap.value = new AMap.Map(`container-${props.mid}`, {
			viewMode: props.viewMode,
			zoom: props.zoom,
			// 地图俯仰角度
			pitch: props.pitch,
			mapStyle: `amap://styles/${props.mapStyle}`
		})

		gaodeMouseTool.value = new AMap.MouseTool(gaodeMap.value)

		gaodeMouseTool.value.on('draw', (event) => {
			mouseToolClose()
			editor = gaodeMap.value.plugin(['AMap.PolyEditor'], () => {})
			mouseToolClose()
			event.obj.on('click', (e) => {
				polygon = e.target
				mouseToolClose()
				closeEdit()
				getPolygonPoints(e.target)
				enablePolyEdit(e, polygon)
			})
		})

		// 中心点
		if (props.center) {
			gaodeMap.value.setCenter(props.center)
		}

		// 控件
		props.plugins.length > 0 && initControlPlugin()
		// 地图初始化完成
		gaodeMap.value.on('complete', () => {
			emits('complete')
		})
	}

	// 初始化 控制控件
	const initControlPlugin = () => {
		// 工具条，控制地图的缩放、平移等
		props.plugins.includes('AMap.ToolBar') && gaodeMap.value.addControl(new AMap.ToolBar({}))
		// 比例尺
		props.plugins.includes('AMap.Scale') && gaodeMap.value.addControl(new AMap.Scale())
		// 鹰眼，显示缩略图
		props.plugins.includes('AMap.HawkEye') && gaodeMap.value.addControl(new AMap.HawkEye({ isOpen: true }))
		// 图层切换
		props.plugins.includes('AMap.MapType') && gaodeMap.value.addControl(new AMap.MapType({}))
		// 定位
		props.plugins.includes('AMap.Geolocation') && gaodeMap.value.addControl(new AMap.Geolocation({}))
	}

	// 渲染 点标记
	const renderMarker = (dataArr) => {
		dataArr.forEach((d) => {
			const marker = new AMap.Marker({
				map: gaodeMap.value,
				position: d.position,
				// 鼠标滑过点标记时的文字提示
				title: d.title,
				// 显示内容：content有效时，icon属性将被覆盖
				content: d.content,
				// 图标
				icon: d.icon ? d.icon : null,
				// 文本标注
				label: d.label
			})
			marker.on('click', () => {
				emits('markerClick', d.position)
			})
			gaodeMapMarkerArr.value.push(marker)
		})

		setFitView()
	}

	// 渲染 圆点标记
	const renderCircleMarker = (dataArr) => {
		dataArr.forEach((d) => {
			const marker = new AMap.CircleMarker({
				map: gaodeMap.value,
				// 圆心位置
				center: d.position,
				// 圆点半径
				radius: d.radius ? d.radius : 20,
				// 线条颜色
				strokeColor: d.strokeColor ? d.strokeColor : '#006600',
				// 轮廓线透明度
				strokeOpacity: 0.5,
				// 轮廓线宽度
				strokeWeight: 2,
				// 填充颜色
				fillColor: d.fillColor ? d.fillColor : '#006600',
				// 填充透明度
				fillOpacity: 0.5,
				cursor: 'pointer'
			})
			marker.on('click', () => {
				emits('markerClick', d.position)
			})
			gaodeMapMarkerArr.value.push(marker)
		})

		setFitView()
	}

	// 渲染 简单点标记
	const renderSimpleMarker = (dataArr, theme = 'default') => {
		dataArr.forEach((d) => {
			const marker = new AMapUI.SimpleMarker({
				map: gaodeMap.value,
				position: d.position,
				// 前景文字
				iconLabel: {
					// 文本
					innerHTML: d.label,
					// 字体的样式，比如颜色，大小等
					style: d.labelStyle
						? d.labelStyle
						: {
								color: '#333',
								fontSize: '12px'
						  }
				},
				// 图标主题：default，fresh，numv1，numv2
				iconTheme: theme,
				// 背景图标样式
				iconStyle: d.style
			})
			marker.on('click', () => {
				emits('markerClick', d.position)
			})
			gaodeMapMarkerArr.value.push(marker)
		})

		setFitView()
	}

	// 渲染 字体点标记
	const renderAwesomeMarker = (dataArr) => {
		dataArr.forEach((d) => {
			const marker = new AMapUI.AwesomeMarker({
				map: gaodeMap.value,
				position: d.position,
				// 图标，参见：http://fontawesome.io/icons/
				awesomeIcon: d.awesomeIcon,
				// 字体的样式，比如颜色，大小等
				iconLabel: {
					style: d.labelStyle
						? d.labelStyle
						: {
								color: '#333',
								fontSize: '12px'
						  }
				},
				// 背景图标的样式
				iconStyle: d.style
			})
			marker.on('click', () => {
				emits('markerClick', d.position)
			})
			gaodeMapMarkerArr.value.push(marker)
		})

		setFitView()
	}

	// 设置 视图级别
	const setFitView = () => {
		// 点聚合
		props.markerCluster && new AMap.MarkerCluster(gaodeMap.value, gaodeMapMarkerArr.value)

		// 根据地图上添加的覆盖物分布情况，自动缩放地图到合适的视野级别
		gaodeMap.value.setFitView(gaodeMapMarkerArr.value)
	}

	// 渲染 线
	const renderPolyline = (dataArr, option = {}) => {
		const path = []
		dataArr.forEach((d) => {
			path.push(new AMap.LngLat(d.position[0], d.position[1]))
		})

		const polyline = new AMap.Polyline({
			path: path,
			strokeColor: option.strokeColor || 'blue',
			strokeWeight: option.strokeWeight || 2,
			strokeOpacity: option.strokeOpacity || 0.5,
			isOutline: option.isOutline || false,
			borderWeight: option.borderWeight || 1,
			// 折线拐点连接处样式
			lineJoin: 'round'
		})
		gaodeMap.value.add(polyline)

		gaodeMap.value.setFitView([polyline])
	}

	// 渲染 圆
	const renderCircle = (position, radius, option) => {
		const circle = new AMap.Circle({
			center: new AMap.LngLat(position[0], position[1]),
			radius: radius,
			strokeColor: option.strokeColor || 'blue',
			strokeWeight: option.strokeWeight || 2,
			strokeOpacity: option.strokeOpacity || 0.5,
			fillColor: option.fillColor || 'blue',
			fillOpacity: option.fillOpacity || 0.5,
			strokeStyle: 'solid'
		})
		gaodeMap.value.add(circle)

		gaodeMap.value.setFitView([circle])
	}

	// 渲染 面
	const renderPolygon = (dataArr, option = {}) => {
		const path = []
		dataArr.forEach((d) => {
			path.push(new AMap.LngLat(d.position[0], d.position[1]))
		})

		const polygon = new AMap.Polygon({
			path: path,
			strokeColor: option.strokeColor || 'blue',
			strokeWeight: option.strokeWeight || 2,
			strokeOpacity: option.strokeOpacity || 0.5,
			fillColor: option.fillColor || 'blue',
			fillOpacity: option.fillOpacity || 0.5,
			strokeStyle: 'solid'
		})
		gaodeMap.value.add(polygon)

		gaodeMap.value.setFitView([polygon])
	}

	// 渲染 信息窗体
	const renderInfoWindow = (dataArr) => {
		dataArr.forEach((d) => {
			gaodeMapInfoWindowObj.value[d.position] = new AMap.InfoWindow({
				// 显示内容
				content: d.content.join('<br>'),
				// 位置偏移量
				offset: new AMap.Pixel(0, -20),
				// 点击地图后关闭信息窗体
				closeWhenClickMap: true
			})
		})
	}

	// 打开 信息窗体
	const openInfoWindow = (position) => {
		const infoWindow = gaodeMapInfoWindowObj.value[position]
		if (infoWindow) {
			infoWindow.open(gaodeMap.value, position)
		}
	}

	// 清理 覆盖物
	const clearOverlay = () => {
		gaodeMap.value.clearMap()
	}

	// 开始绘制
	const gaodeMapDrag = () => {
		gaodeMouseDagFlag = true
		closeEdit()
		gaodeMouseTool.value.polygon({
			strokeColor: '#FF33FF',
			strokeWeight: 6,
			strokeOpacity: 0.2,
			fillColor: '#1791fc',
			fillOpacity: 0.4,
			strokeStyle: 'solid'
		})
	}

	// 关闭绘制功能
	const mouseToolClose = () => {
		gaodeMouseTool.value.close()
	}

	const enablePolyEdit = (e, polygon) => {
		setTimeout(() => {
			editor = new AMap.PolyEditor(gaodeMap.value, polygon)
			editor.open()

			editor.on('addnode', function (event) {
				getPolygonPoints(e.target)
			})

			editor.on('adjust', function (event) {
				getPolygonPoints(e.target)
			})

			editor.on('removenode', function (event) {
				getPolygonPoints(e.target)
			})
		}, 100)
	}

	const remmovePolygon = (flag) => {
		if (flag) {
			gaodeMouseTool.value.close(true)
		} else {
			if (!polygon) {
				message.error('当前未选中面')
				return
			}
			closeEdit()
			gaodeMap.value && gaodeMap.value.remove(polygon)
		}
	}

	const closeEdit = () => {
		editor && editor.CLASS_NAME === 'AMap.PolyEditor' && editor.close()
		checkPoints = []
	}

	const exportFile = (po) => {
		if (!polygon && !po) {
			message.error('当前未选中可导出的面')
			return
		}
		if (po) {
			getPolygonPoints(po)
		} else {
			getPolygonPoints(polygon)
		}
		const str = checkPoints
			.map((d) => {
				return d.join(' ')
			})
			.join(',')

		let blob = new Blob([str], { type: 'text/plain;charset=utf-8' })

		/// 创建一个下载链接
		const url = window.URL.createObjectURL(blob)
		const link = document.createElement('a')
		link.href = url
		link.setAttribute('download', po ? areaInfo.value.name + '.json' : 'file.json') // 设置下载文件的名字

		// 将链接添加到 DOM，并触发点击下载
		document.body.appendChild(link)
		link.click()

		// 释放 URL 对象
		window.URL.revokeObjectURL(url)
		document.body.removeChild(link)
	}

	//地点搜索
	const search = (val) => {
		AMap.plugin(['AMap.PlaceSearch'], function () {
			//构造地点查询类
			var placeSearch = new AMap.PlaceSearch({
				pageSize: 5, // 单页显示结果条数
				pageIndex: 1, // 页码
				map: gaodeMap.value, // 展现结果的地图实例
				panel: 'panel', // 结果列表将在此容器中进行展示。
				autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
			})
			//关键字查询
			placeSearch.search(val, function (status, result) {
				console.log(result)
			})
		})
	}

	const areaType = ref('city')
	const areaInfo = ref({
		show: false,
		citycode: '',
		adcode: '',
		level: '',
		name: ''
	})
	//区域搜索
	const areaSearch = (val) => {
		if (!val) {
			if (gaodeMap.value && areaInfo.value.polygon) {
				areaInfo.value.polygon.visible = false
				gaodeMap.value && gaodeMap.value.remove(areaInfo.value.polygon)
			}
			areaInfo.value = {
				show: false,
				citycode: '',
				adcode: '',
				level: '',
				name: ''
			}
			return
		}
		//引入插件，此示例采用异步引入，更多引入方式 https://lbs.amap.com/api/javascript-api-v2/guide/abc/plugins
		AMap.plugin('AMap.DistrictSearch', function () {
			var districtSearch = new AMap.DistrictSearch({
				level: areaType.value, //关键字对应的行政区级别，country 表示国家province：省/直辖市	city：市district：区/县	biz_area：商圈
				subdistrict: 1, //显示下级行政区级数，1表示返回下一级行政区
				extensions: 'all' //返回行政区边界坐标组等具体信息
			})
			//搜索所有省、直辖市信息
			districtSearch.search(val, function (status, result) {
				//status：complete 表示查询成功，no_data 为查询无结果，error 代表查询错误
				if (status !== 'complete') {
					message.warn('查询无结果')
					return
				}
				const data = (result.districtList.filter((item) => item.level === areaType.value) || [{}])[0]
				console.log(data)
				if (!data) return
				if (gaodeMap.value && areaInfo.value.polygon) {
					areaInfo.value.polygon.visible = false
					gaodeMap.value && gaodeMap.value.remove(areaInfo.value.polygon)
				}
				areaInfo.value = {
					show: true,
					citycode: data.citycode,
					adcode: data.adcode,
					level: data.level,
					name: data.name,
					center: data.center,
					polygon: ''
				}
				//查询成功时，result 即为对应的行政区信息
				var bounds = data.boundaries //获取边界信息
				if (bounds) {
					for (var i = 0; i < bounds.length; i++) {
						//生成行政区划 polygon
						var polygon = new AMap.Polygon({
							map: gaodeMap.value, //显示该覆盖物的地图对象
							strokeWeight: 1, //轮廓线宽度
							path: bounds[i], //多边形轮廓线的节点坐标数组
							fillOpacity: 0.7, //多边形填充透明度
							fillColor: '#CCF3FF', //多边形填充颜色
							strokeColor: '#CC66CC' //线条颜色
						})
					}
					gaodeMap.value.add(polygon)
					areaInfo.value.polygon = polygon
					gaodeMap.value.setFitView() //将覆盖物调整到合适视野
				}
			})
		})
	}

	const areaModal = reactive({
		open: false,
		area: '',
		checkPoints: ''
	})
	//计算面积
	const ringArea = () => {
		if (!polygon) {
			message.error('当前未选中可导出的面')
			return
		}
		getPolygonPoints(polygon)
		areaModal.open = true
		areaModal.checkPoints = checkPoints
		areaModal.area = Math.round(AMap.GeometryUtil.ringArea(checkPoints))
	}

	onMounted(() => {
		init()
	})

	onUnmounted(() => {
		gaodeMap.value && gaodeMap.value.destroy()
	})

	defineExpose({
		renderMarker,
		renderCircleMarker,
		renderSimpleMarker,
		renderAwesomeMarker,
		renderPolyline,
		renderCircle,
		renderPolygon,
		renderInfoWindow,
		openInfoWindow,
		clearOverlay,
		gaodeMapDrag,
		mouseToolClose,
		remmovePolygon,
		exportFile,
		closeEdit,
		ringArea
	})
</script>

<style lang="less">
	.xn-wh {
		width: 100%;
		height: 100%;
	}
	.gaodeMap {
		padding: 0;
		margin: 0;
		width: 100%;
		height: 100%;
		position: relative;

		input[type='radio'] {
			-webkit-appearance: radio;
		}

		input[type='checkbox'] {
			-webkit-appearance: checkbox;
		}
	}
	.areaInfo {
		position: absolute;
		width: 60%;
		bottom: 0;
		right: 0;
		min-height: 100px;
		background: #fff;
	}
</style>
<style scoped>
	#panel {
		position: absolute;
		background-color: white;
		max-height: 90%;
		overflow-y: auto;
		top: 186px;
		right: 0px;
		width: 300px;
	}
</style>
